﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using ZOVNP.Model.Abstracts;

namespace ZOVNP.WinView
{
    /// <summary> Форма логина на сервер </summary>
    [Description("Форма логина на сервер")]
    public sealed class LoginForm : Form
    {
        #region Поля

        #region Const

        private const string LABEL_NAME = "LabelName";
        private const string LABEL_PASSWORD = "LabelPassword";
        private const string LABEL_DATASOURCE = "LabelDataSource";
        private const string LABEL_INITIALCATALOG = "LabelInitialCatalog";
        private const string LABEL_EXTEND = "LabelExtend";
        private const string LABEL_INTEGRATEDSECURITY = "LabelIntegratedSecurity";
        private const string CAPTION_TEXT = "CaptionText";
        private const string OK_TEXT = "OkText";
        private const string CANCEL_TEXT = "CancelText";
        private const string LOGO = "Logo";
        private const string BAND = "Band";
        private const string ARGUMENT_NULL = "ArgumentNull";
        private const string NOT_CONNECTED = "NotConnected";
        private const int CLIENT_WIDTH = 413;

        #endregion

        /// <summary> Поле имени пользователя </summary>
        private TextBox m_txtUserID;
        /// <summary> Поле пароля </summary>
        private TextBox m_txtPassword;
        /// <summary> Список серверов </summary>
        private ComboBox m_cbxDataSource;
        /// <summary> Список БД </summary>
        private ComboBox m_cbxInitialCatalog;
        /// <summary> Флаг SSPI </summary>
        private CheckBox m_chkIntegratedSecurity;
        /// <summary> Кнопка ОК </summary>
        private Button m_btnOK;
        /// <summary> Кнопка Cancel </summary>
        private Button m_btnCancel;
        /// <summary> Кнопка группы дополнительных параметров </summary>
        private Button m_btnExtend;
        /// <summary> Полоса (картинка) </summary>
        private PictureBox m_picBand;
        /// <summary> Смещение полоски </summary>
        private int m_shift;
        /// <summary> Класс логина </summary>
        private Login m_login;
        /// <summary> Таблица </summary>
        private TableLayoutPanel m_tblLayoutPanel;
        /// <summary> Label списка серверов </summary>
        private Label m_lblDataSource;
        /// <summary> Label списка БД </summary>
        private Label m_lblInitialCatalog;
        /// <summary> Менеджер ресурсов </summary>
        private ComponentResourceManager m_res;

        #endregion

        /// <summary> Конструктор </summary>
        /// <param name="login"> логин </param>
        public LoginForm(Login login)
        {
            m_res = new ComponentResourceManager(typeof (LoginForm));
            if (login == null)
                throw new ArgumentNullException("login", m_res.GetString(ARGUMENT_NULL));

            m_login = login;
            m_login.SynchronizationContext = WindowsFormsSynchronizationContext.Current;
            Subscribe();

            this.SuspendLayout();
            base.Font = SystemFonts.IconTitleFont;
            base.ShowInTaskbar = true;

            // m_tblLayoutPanel
            m_tblLayoutPanel = new TableLayoutPanel();
            m_tblLayoutPanel.SuspendLayout();
            m_tblLayoutPanel.Padding = new Padding(10);
            //m_tblLayoutPanel.CellBorderStyle = TableLayoutPanelCellBorderStyle.Single;
            m_tblLayoutPanel.AutoSize = true;
            m_tblLayoutPanel.Dock = DockStyle.Top;
            m_tblLayoutPanel.ColumnCount = 5;
            m_tblLayoutPanel.RowCount = 7;
            m_tblLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
            m_tblLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
            m_tblLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 25F));
            m_tblLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
            m_tblLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
            // по-умолчанию все строки AutoSize

            // Labels
            Label lblUser = CreateLabel(m_res.GetString(LABEL_NAME));
            Label lblPassword = CreateLabel(m_res.GetString(LABEL_PASSWORD));
            m_lblDataSource = CreateLabel(m_res.GetString(LABEL_DATASOURCE));
            m_lblInitialCatalog = CreateLabel(m_res.GetString(LABEL_INITIALCATALOG));
            Label lblExtend = CreateLabel(m_res.GetString(LABEL_EXTEND));

            // m_txtUserID
            m_txtUserID = new TextBox();
            m_txtUserID.TabIndex = 0;
            m_txtUserID.Dock = DockStyle.Fill;
            m_txtUserID.DataBindings.Add(new Binding("Text", m_login, "UserID", false, DataSourceUpdateMode.OnPropertyChanged));
            m_txtUserID.DataBindings.Add(new Binding("Enabled", m_login, "UserIDPasswordEnabled"));

            // m_txtPassword
            m_txtPassword = new TextBox();
            m_txtPassword.TabIndex = 1;
            m_txtPassword.Dock = DockStyle.Fill;
            m_txtPassword.UseSystemPasswordChar = true;
            m_txtPassword.DataBindings.Add(new Binding("Text", m_login, "Password"));
            m_txtPassword.DataBindings.Add(new Binding("Enabled", m_login, "UserIDPasswordEnabled"));

            // m_cbxDataSource
            m_cbxDataSource = new ComboBox();
            m_cbxDataSource.FlatStyle = FlatStyle.System;
            m_cbxDataSource.Dock = DockStyle.Fill;
            m_cbxDataSource.TabIndex = 2;
            m_cbxDataSource.DataSource = m_login.DataSource;
            m_cbxDataSource.DataBindings.Add("Text", m_login, "CurrentDataSource", false, DataSourceUpdateMode.OnPropertyChanged);
            m_cbxDataSource.DataBindings.Add("Enabled", m_login, "IsNotBusy", false, DataSourceUpdateMode.OnPropertyChanged);

            // m_cbxInitialCatalog
            m_cbxInitialCatalog = new ComboBox(); //new CaseSensitiveComboBox();
            m_cbxInitialCatalog.FlatStyle = FlatStyle.System;
            m_cbxInitialCatalog.Dock = DockStyle.Fill;
            m_cbxInitialCatalog.TabIndex = 3;
            m_cbxInitialCatalog.DataSource = m_login.InitialCatalog;
            m_cbxInitialCatalog.DataBindings.Add("Text", m_login, "CurrentInitialCatalog", false, DataSourceUpdateMode.OnPropertyChanged);
            m_cbxInitialCatalog.DataBindings.Add("Enabled", m_login, "IsNotBusy", false, DataSourceUpdateMode.OnPropertyChanged);

            // m_btnOK
            m_btnOK = new Button();
            m_btnOK.FlatStyle = FlatStyle.System;
            m_btnOK.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
            m_btnOK.TabIndex = 4;
            m_btnOK.Text = m_res.GetString(OK_TEXT);
            m_btnOK.Click += delegate { m_login.ConnectAsync(); };
            m_btnOK.DataBindings.Add(new Binding("Enabled", m_login, "Enabled"));

            // m_btnCancel
            m_btnCancel = new Button();
            m_btnCancel.FlatStyle = FlatStyle.System;
            m_btnCancel.TabIndex = 5;
            m_btnCancel.Text = m_res.GetString(CANCEL_TEXT);
            m_btnCancel.Click += OnCancelClick;
            m_btnCancel.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;

            // m_btnExtend
            m_btnExtend = new Button();
            m_btnExtend.FlatStyle = FlatStyle.System;
            //m_btnExtend.AutoSize = true;
            m_btnExtend.Size = new Size(16, 16);
            m_btnExtend.TabIndex = 6;
            m_btnExtend.Click += delegate { this.VisibleExtendedGroup = !this.VisibleExtendedGroup; };
            m_btnExtend.DataBindings.Add(new Binding("Enabled", m_login, "IsNotBusy"));

            // m_chkIntegratedSecurity
            m_chkIntegratedSecurity = new CheckBox();
            m_chkIntegratedSecurity.TabIndex = 7;
            m_chkIntegratedSecurity.Text = m_res.GetString(LABEL_INTEGRATEDSECURITY);
            m_chkIntegratedSecurity.TextAlign = ContentAlignment.MiddleLeft;
            m_chkIntegratedSecurity.Dock = DockStyle.Fill;
            m_chkIntegratedSecurity.DataBindings.Add(new Binding("Checked", m_login, "IntegratedSecurity", false,
                                                                 DataSourceUpdateMode.OnPropertyChanged));
            m_chkIntegratedSecurity.DataBindings.Add(new Binding("Enabled", m_login, "IsNotBusy"));

            // m_picLogo
            PictureBox picLogo = new PictureBox();
            picLogo.Dock = DockStyle.Top;
            picLogo.BackgroundImage = (Image) (m_res.GetObject(LOGO));
            picLogo.Height = picLogo.BackgroundImage.Height;
            picLogo.SizeMode = PictureBoxSizeMode.StretchImage;

            m_picBand = new PictureBox();
            m_picBand.Dock = DockStyle.Top;
            m_picBand.Image = (Image) (m_res.GetObject(BAND));
            m_picBand.Height = m_picBand.Image.Height;
            //m_picBand.DoubleBuffered = false;

            // добавляем все в таблицу
            TableLayoutControlCollection cc = m_tblLayoutPanel.Controls;
            cc.Add(lblUser, 1, 0);
            cc.Add(m_txtUserID, 2, 0);
            m_tblLayoutPanel.SetColumnSpan(m_txtUserID, 3);
            cc.Add(lblPassword, 1, 1);
            cc.Add(m_txtPassword, 2, 1);
            m_tblLayoutPanel.SetColumnSpan(m_txtPassword, 3);
            cc.Add(m_chkIntegratedSecurity, 1, 2);
            m_tblLayoutPanel.SetColumnSpan(m_chkIntegratedSecurity, 3);
            cc.Add(m_btnExtend, 0, 3);
            cc.Add(lblExtend, 1, 3);
            m_tblLayoutPanel.SetColumnSpan(lblExtend, 3);
            cc.Add(m_lblDataSource, 1, 4);
            cc.Add(m_lblInitialCatalog, 1, 5);
            cc.Add(m_cbxDataSource, 2, 4);
            m_tblLayoutPanel.SetColumnSpan(m_cbxDataSource, 3);
            cc.Add(m_cbxInitialCatalog, 2, 5);
            m_tblLayoutPanel.SetColumnSpan(m_cbxInitialCatalog, 3);
            cc.Add(m_btnOK, 3, 6);
            cc.Add(m_btnCancel, 4, 6);

            // formLogin
            this.ShowIcon = false;
            //this.AutoScaleDimensions = new SizeF(6F, 13F);
            this.AcceptButton = m_btnOK;
            //this.AutoScaleMode = AutoScaleMode.Font;
            this.Controls.Add(m_tblLayoutPanel);
            this.Controls.Add(m_picBand);
            this.Controls.Add(picLogo);
            m_tblLayoutPanel.ResumeLayout();
            this.FormBorderStyle = FormBorderStyle.FixedDialog;
            this.MaximizeBox = false;
            this.MinimizeBox = false;
            this.Name = "LoginForm";
            this.StartPosition = FormStartPosition.CenterParent;
            this.Text = m_res.GetString(CAPTION_TEXT);
            this.ResumeLayout(false);
            this.PerformLayout();
            
            m_login.IntegratedSecurity = true;
            m_login.CurrentDataSource = "(local)";
            m_login.CurrentInitialCatalog = "zovnp";
        }

        /// <summary> Обработчик открытия формы </summary>
        /// <param name="e"> параметры события </param>
        protected override void OnShown(EventArgs e)
        {
            base.OnShown(e);
            this.VisibleExtendedGroup = !m_login.IsValidDataSourceInitialCatalog;
            this.Top = (int)(System.Windows.SystemParameters.PrimaryScreenHeight / 2 - this.Height / 2);
            this.Left = (int)(System.Windows.SystemParameters.PrimaryScreenWidth / 2 - this.Width / 2);


            if (!m_chkIntegratedSecurity.Checked)
            {
                if (this.IsValidFieldUserId())
                    m_txtPassword.Select();
                else
                    m_txtUserID.Select();
            }
        }
        /// <summary> Обработчик закрытия формы </summary>
        /// <param name="e"> параметры события </param>
        protected override void OnClosed(EventArgs e)
        {
            Unsubscribe();
            base.OnClosed(e);
        }
        /// <summary> Получить (установить) признак показа группы дополнительных параметров </summary>
        /// <value> флаг показа </value>
        private bool VisibleExtendedGroup
        {
            get { return (m_cbxDataSource.Visible); }
            set
            {
                m_btnExtend.Text = value ? "-" : "+";
                m_lblDataSource.Visible = m_lblInitialCatalog.Visible = m_cbxDataSource.Visible = m_cbxInitialCatalog.Visible = value;
                m_cbxInitialCatalog.TabStop = value;
                m_cbxDataSource.TabStop = value;

                this.ClientSize = new Size(CLIENT_WIDTH, m_tblLayoutPanel.Bottom);

                if (!value)
                    m_txtPassword.Focus();
            }
        }
        /// <summary> Обработчик нажатия кнопки Cancel </summary>
        /// <param name="sender"> источник события </param>
        /// <param name="e"> параметры события </param>
        private void OnCancelClick(object sender, EventArgs e)
        {
            // Отмена установки соединения или логина ?
            if (m_login.IsBusy)
            {
                Cursor.Current = Cursors.WaitCursor;
                m_login.Cancel();
            }
            else
                Close();
        }
        /// <summary> Обработчик события выполнения соединения </summary>
        /// <param name="state"> параметры события </param>
        private void OnConnecting(object state)
        {
            using (Graphics g = m_picBand.CreateGraphics())
            {
                m_shift += 8;
                if (m_shift >= m_picBand.Width)
                    m_shift = 8;
                g.DrawImageUnscaled(m_picBand.Image, m_shift - m_picBand.Width, 0);
                g.DrawImageUnscaled(m_picBand.Image, m_shift + 1, 0);
            }
        }
        /// <summary> Получить признак введенного логина пользователя </summary>
        /// <returns> true, если введен, в противном случае - false </returns>
        private bool IsValidFieldUserId() { return (!String.IsNullOrEmpty(m_txtUserID.Text)); }
        /// <summary> Получить признак введенного пароля </summary>
        /// <value> true, если введен, в противном случае - false </value>
        private bool IsValidFieldPassword() { return (!String.IsNullOrEmpty(m_txtPassword.Text)); }
        /// <summary> Обработчик события завершения выполнения соединения с источником данных </summary>
        /// <param name="sender"> источник события </param>
        /// <param name="e"> параметры события </param>
        private void OnConnectCompleted(object sender, AsyncCompletedEventArgs e)
        {
            // если не было отмены
            if (!e.Cancelled)
            {
                if (e.Error != null)
                {
                    if (e.Error is PasswordException) // требуется смена пароля
                    {
                        new ServiceLocatorHelper().ServiceLocator.GetService<IMessageService>().ShowMessage(e.Error.Message);
                        using (ChangePasswordForm form = new ChangePasswordForm(m_login))
                        {
                            if (form.ShowDialog() == DialogResult.OK)
                            {
                                m_login.ConnectAsync();
                            }
                            else
                                Close(); // закрываемся, но дальше что он будет делать?
                        }
                    }
                    else
                        new ServiceLocatorHelper().ServiceLocator.GetService<IMessageService>().ShowAllErrors(e.Error, String.Format(m_res.GetString(NOT_CONNECTED), m_login.CurrentDataSource));
                }
                else
                    Close();
            }
        }
        ///// <summary> Обработчик события необходимости выбора сервера </summary>
        ///// <param name="sender"> источник события </param>
        ///// <param name="e"> параметры события </param>
        //private void OnDataSourceNeeded(object sender, DataSourceNeededEventArgs e)
        //{
        //    SQLServerInfo result = new formBrowseServers(e.AvailableDataSourceEnumerator).GetDataSource();
        //    if (result != null)
        //        e.DataSource = result.Key;
        //}
        /// <summary> Подписаться на события модели </summary>
        private void Subscribe()
        {
            m_login.ConnectCompleted += OnConnectCompleted;
            m_login.DoConnect += OnConnecting;
            //m_login.DataSourceNeeded += OnDataSourceNeeded;
        }
        /// <summary> Снять подписку на события модели </summary>
        private void Unsubscribe()
        {
            m_login.ConnectCompleted -= OnConnectCompleted;
            m_login.DoConnect -= OnConnecting;
            //m_login.DataSourceNeeded -= OnDataSourceNeeded;
        }
        /// <summary> Создать Label </summary>
        /// <param name="text"> текст </param>
        /// <returns> новый экземпляр Label</returns>
        private static Label CreateLabel(string text)
        {
            Label result = new Label();
            result.Text = text;
            result.TextAlign = ContentAlignment.MiddleLeft;
            result.Dock = DockStyle.Fill;
            return (result);
        }
    }
}
